package hotel.board.circuit;

import hotel.HotelConstants;
import hotel.board.circuit.predefined.IPredefinedCircuit;
import hotel.exception.BuildingsMissingException;
import hotel.exception.NotEnoughPlaceException;
import hotel.player.IPlayer;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Circuit implements IModifiableCircuit, HotelConstants {
	
	// ATTRIBUTS
	
	private final List<IModifiableCase> cases;
	private final IPlayer[] players;
	private final Map<IPlayer, ICase> playersToCases;
	private final Map<ICase, IPlayer> casesToPlayers;
	private final int bankPosition;
	private final int cityHallPosition;
	private boolean passedBank;
	private boolean passedCityHall;
	
	// CONSTRUCTEUR
	
	public Circuit(IPlayer[] players, ICase[] c, int bankPos, int cityHallPos) {
		// Cases du circuit
		cases = new ArrayList<IModifiableCase>();
		for (int i = 0; i < c.length; ++i) {
			cases.add(new ModifiableCase(c[i]));
		}
		// Joueurs
		this.players = players.clone();
		// Position des joueurs
		playersToCases = new HashMap<IPlayer, ICase>();
		casesToPlayers = new HashMap<ICase, IPlayer>();
		for (IPlayer pl : this.players) {
			playersToCases.put(pl, STARTING_CASE);
		}
		// Positions
		bankPosition = bankPos;
		cityHallPosition = cityHallPos;
	}
	
	public Circuit(IPlayer[] players, IPredefinedCircuit circuit) {
		this(players, circuit.getCases(), circuit.getBankPosition(), circuit.getCityHallPosition());
	}
	
	// REQUETES

	@Override
	public int getCircuitLength() {
		return cases.size();
	}

	@Override
	public ICase[] getCases() {
		return cases.toArray(new ICase[0]);
	}

	@Override
	public IPlayer[] getPlayers() {
		return players;
	}

	@Override
	public IPlayer getPlayer(ICase c) {
		return casesToPlayers.get(c);
	}

	@Override
	public ICase getCase(IPlayer p) {
		ICase c = playersToCases.get(p);
		if (c == null) {
			return STARTING_CASE;
		}
		return c;
	}

	@Override
	public int getBankPosition() {
		return bankPosition;
	}

	@Override
	public int getCityHallPosition() {
		return cityHallPosition;
	}
	
	@Override
	public boolean passedBank() {
		return passedBank;
	}
	
	@Override
	public boolean passedCityHall() {
		return passedCityHall;
	}
	
	// COMMANDES

	@Override
	public ICase advance(IPlayer p, int i) {
		int old = cases.indexOf(getCase(p));
		ICase oldCase;
		ICase nextCase;
		if (old != -1) {
			while (getPlayer(cases.get(old + i)) != null) {
				i++;
			}
			oldCase = cases.get(old);
			nextCase = cases.get((old + i) % cases.size());
		} else {
			while (getPlayer(cases.get(i)) != null) {
				i++;
			}
			oldCase = STARTING_CASE;
			nextCase = cases.get(i % cases.size());
		}
		passedBank = old <= bankPosition && old + i > bankPosition;
		passedCityHall = old <= cityHallPosition && old + i > cityHallPosition;
		playersToCases.put(p, nextCase);
		casesToPlayers.remove(oldCase);
		casesToPlayers.put(nextCase, p);
		return nextCase;
	}

	@Override
	public void buildEntry(ICase c, int side) throws NotEnoughPlaceException, BuildingsMissingException {
		cases.get(cases.indexOf(c)).buildEntry(side);
	}
	
	@Override
	public void initPassed() {
		passedBank = false;
		passedCityHall = false;
	}

}
